﻿#include <QCoreApplication>
#include <QDateTime>
#include <QFile>
#include <QLibrary>
#include <QMutex>
#include <QSemaphore>
#include <QProcess>
#include <QSettings>
#include <QTextStream>
#include <qt_windows.h>
#include <QWaitCondition>
#include <QAbstractEventDispatcher>
#include <QVector>
#include <QThread>
#include <QTimer>
#include <QDebug>

#include "qtservicebase_p.h"
#include "qtservicebase.h"
#include "qtserviceprivate.h"

extern PRegisterServiceCtrlHandler pRegisterServiceCtrlHandler;
extern PSetServiceStatus pSetServiceStatus;
extern PChangeServiceConfig2 pChangeServiceConfig2;
extern PCloseServiceHandle pCloseServiceHandle;
extern PCreateService pCreateService;
extern POpenSCManager pOpenSCManager;
extern PDeleteService pDeleteService;
extern POpenService pOpenService;
extern PQueryServiceStatus pQueryServiceStatus;
extern PStartServiceCtrlDispatcher pStartServiceCtrlDispatcher;
extern PStartService pStartService;
extern PControlService pControlService;
extern PDeregisterEventSource pDeregisterEventSource;
extern PReportEvent pReportEvent;
extern PRegisterEventSource pRegisterEventSource;
extern PRegisterServiceProcess pRegisterServiceProcess;
extern PQueryServiceConfig pQueryServiceConfig;
extern PQueryServiceConfig2 pQueryServiceConfig2;

extern bool winServiceInit();

Q_GLOBAL_STATIC(QtServiceAppEventFilter, qtServiceAppEventFilter);

QtServiceBasePrivate::QtServiceBasePrivate(const QString &name)
    : startupType(QtServiceController::ManualStartup), serviceFlags(0), controller(name)
{

}

QtServiceBasePrivate::~QtServiceBasePrivate()
{

}

void QtServiceBasePrivate::startService()
{
    q_ptr->start();
}

int QtServiceBasePrivate::run(bool asService, const QStringList &argList)
{
    int argc = argList.size();
    QVector<char *> argv(argc);
    QList<QByteArray> argvData;
    for (int i = 0; i < argc; ++i)
        argvData.append(argList.at(i).toLocal8Bit());
    for (int i = 0; i < argc; ++i)
        argv[i] = argvData[i].data();

    if (asService && !sysInit())
        return -1;

    q_ptr->createApplication(argc, argv.data());
    QCoreApplication *app = QCoreApplication::instance();
    if (!app)
        return -1;

    if (asService)
        sysSetPath();

    QtServiceStarter starter(this);
    QTimer::singleShot(0, &starter, SLOT(slotStart()));
    int res = q_ptr->executeApplication();
    delete app;

    if (asService)
        sysCleanup();
    return res;
}


bool QtServiceBasePrivate::start()
{
    sysInit();
    if (!winServiceInit())
        return false;

    // Since StartServiceCtrlDispatcher() blocks waiting for service
    // control events, we need to call it in another thread, so that
    // the main thread can run the QApplication event loop.
    HandlerThread* ht = new HandlerThread();
    ht->start();

    QtServiceSysPrivate* sys = QtServiceSysPrivate::instance;

    // Wait until service args have been received by serviceMain.
    // If Windows doesn't call serviceMain (or
    // StartServiceControlDispatcher doesn't return an error) within
    // a timeout of 20 secs, something is very wrong; give up
    if (!sys->startSemaphore.tryAcquire(1, 20000))
        return false;

    if (!ht->calledOk()) {
        if (ht->runningAsConsole())
            return controller.start(args.mid(1));
        else
            return false;
    }

    int argc = sys->serviceArgs.size();
    QVector<char *> argv(argc);
    QList<QByteArray> argvData;
    for (int i = 0; i < argc; ++i)
        argvData.append(sys->serviceArgs.at(i).toLocal8Bit());
    for (int i = 0; i < argc; ++i)
        argv[i] = argvData[i].data();

    q_ptr->createApplication(argc, argv.data());
    QCoreApplication *app = QCoreApplication::instance();
    if (!app)
        return false;

    QAbstractEventDispatcher::instance()->installNativeEventFilter(qtServiceAppEventFilter());

    sys->controllerHandler = new QtServiceControllerHandler(sys);

    sys->startSemaphore2.release(); // let serviceMain continue (and end)

    sys->status.dwWin32ExitCode = q_ptr->executeApplication();
    sys->setStatus(SERVICE_STOPPED);

    if (ht->isRunning())
        ht->wait(1000);         // let the handler thread finish
    delete sys->controllerHandler;
    sys->controllerHandler = 0;
    if (ht->isFinished())
        delete ht;
    delete app;
    sysCleanup();
    return true;
}

bool QtServiceBasePrivate::install(const QString &account, const QString &password)
{
    bool result = false;
    if (!winServiceInit())
        return result;

    // Open the Service Control Manager
    SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS);
    if (hSCM) {
        QString acc = account;
        DWORD dwStartType = startupType == QtServiceController::AutoStartup ? SERVICE_AUTO_START : SERVICE_DEMAND_START;
        DWORD dwServiceType = SERVICE_WIN32_OWN_PROCESS;
        wchar_t *act = 0;
        wchar_t *pwd = 0;
        if (!acc.isEmpty()) {
            // The act string must contain a string of the format "Domain\UserName",
            // so if only a username was specified without a domain, default to the local machine domain.
            if (!acc.contains(QChar('\\'))) {
                acc.prepend(QLatin1String(".\\"));
            }
            if (!acc.endsWith(QLatin1String("\\LocalSystem")))
                act = (wchar_t*)acc.utf16();
        }
        if (!password.isEmpty() && act) {
            pwd = (wchar_t*)password.utf16();
        }

        // Only set INTERACTIVE if act is LocalSystem. (and act should be 0 if it is LocalSystem).
        if (!act) dwServiceType |= SERVICE_INTERACTIVE_PROCESS;

        // Create the service
        SC_HANDLE hService = pCreateService(hSCM, (wchar_t *)controller.serviceName().utf16(),
                                            (wchar_t *)controller.serviceName().utf16(),
                                            SERVICE_ALL_ACCESS,
                                            dwServiceType, // QObject::inherits ( const char * className ) for no inter active ????
                                            dwStartType, SERVICE_ERROR_NORMAL, (wchar_t *)filePath().utf16(),
                                            0, 0, 0,
                                            act, pwd);
        if (hService) {
            result = true;
            if (!serviceDescription.isEmpty()) {
                SERVICE_DESCRIPTION sdesc;
                sdesc.lpDescription = (wchar_t *)serviceDescription.utf16();
                pChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &sdesc);
            }
            pCloseServiceHandle(hService);
        }
        pCloseServiceHandle(hSCM);
    }
    return result;
}

QString QtServiceBasePrivate::filePath() const
{
    wchar_t path[_MAX_PATH];
    ::GetModuleFileNameW( 0, path, sizeof(path) );
    return QString::fromUtf16((unsigned short*)path);
}

bool QtServiceBasePrivate::sysInit()
{
    sysd = new QtServiceSysPrivate();

    sysd->serviceStatus			    = 0;
    sysd->status.dwServiceType		    = SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS;
    sysd->status.dwCurrentState		    = SERVICE_STOPPED;
    sysd->status.dwControlsAccepted         = sysd->serviceFlags(serviceFlags);
    sysd->status.dwWin32ExitCode	    = NO_ERROR;
    sysd->status.dwServiceSpecificExitCode  = 0;
    sysd->status.dwCheckPoint		    = 0;
    sysd->status.dwWaitHint		    = 0;

    return true;
}

void QtServiceBasePrivate::sysSetPath()
{

}

void QtServiceBasePrivate::sysCleanup()
{
    if (sysd) {
        delete sysd;
        sysd = 0;
    }
}


QtServiceBase *QtServiceBasePrivate::instance = 0;

/*!
    \class QtServiceBase

    \brief The QtServiceBase class provides an API for implementing
    Windows services and Unix daemons.

    A Windows service or Unix daemon (a "service"), is a program that
    runs "in the background" independently of whether a user is logged
    in or not. A service is often set up to start when the machine
    boots up, and will typically run continuously as long as the
    machine is on.

    Services are usually non-interactive console applications. User
    interaction, if required, is usually implemented in a separate,
    normal GUI application that communicates with the service through
    an IPC channel. For simple communication,
    QtServiceController::sendCommand() and QtService::processCommand()
    may be used, possibly in combination with a shared settings
    file. For more complex, interactive communication, a custom IPC
    channel should be used, e.g. based on Qt's networking classes. (In
    certain circumstances, a service may provide a GUI itself,
    ref. the "interactive" example documentation).

    Typically, you will create a service by subclassing the QtService
    template class which inherits QtServiceBase and allows you to
    create a service for a particular application type.

    The Windows implementation uses the NT Service Control Manager,
    and the application can be controlled through the system
    administration tools. Services are usually launched using the
    system account, which requires that all DLLs that the service
    executable depends on (i.e. Qt), are located in the same directory
    as the service, or in a system path.

    On Unix a service is implemented as a daemon.

    You can retrieve the service's description, state, and startup
    type using the serviceDescription(), serviceFlags() and
    startupType() functions respectively. The service's state is
    decribed by the ServiceFlag enum. The mentioned properites can
    also be set using the corresponding set functions. In addition you
    can retrieve the service's name using the serviceName() function.

    Several of QtServiceBase's protected functions are called on
    requests from the QtServiceController class:

    \list
        \o start()
        \o pause()
        \o processCommand()
        \o resume()
        \o stop()
    \endlist

    You can control any given service using an instance of the
    QtServiceController class which also allows you to control
    services from separate applications. The mentioned functions are
    all virtual and won't do anything unless they are
    reimplemented. You can reimplement these functions to pause and
    resume the service's execution, as well as process user commands
    and perform additional clean-ups before shutting down.

    QtServiceBase also provides the static instance() function which
    returns a pointer to an application's QtServiceBase instance. In
    addition, a service can report events to the system's event log
    using the logMessage() function. The MessageType enum describes
    the different types of messages a service reports.

    The implementation of a service application's main function
    typically creates an service object derived by subclassing the
    QtService template class. Then the main function will call this
    service's exec() function, and return the result of that call. For
    example:

    \code
        int main(int argc, char **argv)
        {
            MyService service(argc, argv);
            return service.exec();
        }
    \endcode

    When the exec() function is called, it will parse the service
    specific arguments passed in \c argv, perform the required
    actions, and return.

    \target serviceSpecificArguments

    The following arguments are recognized as service specific:

    \table
    \header \i Short \i Long \i Explanation
    \row \i -i \i -install \i Install the service.
    \row \i -u \i -uninstall \i Uninstall the service.
    \row \i -e \i -exec
         \i Execute the service as a standalone application (useful for debug purposes).
            This is a blocking call, the service will be executed like a normal application.
            In this mode you will not be able to communicate with the service from the contoller.
    \row \i -t \i -terminate \i Stop the service.
    \row \i -p \i -pause \i Pause the service.
    \row \i -r \i -resume \i Resume a paused service.
    \row \i -c \e{cmd} \i -command \e{cmd}
     \i Send the user defined command code \e{cmd} to the service application.
    \row \i -v \i -version \i Display version and status information.
    \endtable

    If \e none of the arguments is recognized as service specific,
    exec() will first call the createApplication() function, then
    executeApplication() and finally the start() function. In the end,
    exec() returns while the service continues in its own process
    waiting for commands from the service controller.

    \sa QtService, QtServiceController
*/

/*!
    \enum QtServiceBase::MessageType

    This enum describes the different types of messages a service
    reports to the system log.

    \value Success An operation has succeeded, e.g. the service
           is started.
    \value Error An operation failed, e.g. the service failed to start.
    \value Warning An operation caused a warning that might require user
           interaction.
    \value Information Any type of usually non-critical information.
*/

/*!
    \enum QtServiceBase::ServiceFlag

    This enum describes the different capabilities of a service.

    \value Default The service can be stopped, but not suspended.
    \value CanBeSuspended The service can be suspended.
    \value CannotBeStopped The service cannot be stopped.
    \value NeedsStopOnShutdown (Windows only) The service will be stopped before the system shuts down. Note that Microsoft recommends this only for services that must absolutely clean up during shutdown, because there is a limited time available for shutdown of services.
*/

/*!
    Creates a service instance called \a name. The \a argc and \a argv
    parameters are parsed after the exec() function has been
    called. Then they are passed to the application's constructor.
    The application type is determined by the QtService subclass.

    The service is neither installed nor started. The name must not
    contain any backslashes or be longer than 255 characters. In
    addition, the name must be unique in the system's service
    database.

    \sa exec(), start(), QtServiceController::install()
*/
QtServiceBase::QtServiceBase(int argc, char **argv, const QString &name)
{
#if defined(QTSERVICE_DEBUG)
#  if QT_VERSION >= 0x050000
    qInstallMessageHandler(qtServiceLogDebug);
#  else
    qInstallMsgHandler(qtServiceLogDebug);
#  endif
    qAddPostRoutine(qtServiceCloseDebugLog);
#endif

    Q_ASSERT(!QtServiceBasePrivate::instance);
    QtServiceBasePrivate::instance = this;

    QString nm(name);
    if (nm.length() > 255) {
    qWarning("QtService: 'name' is longer than 255 characters.");
    nm.truncate(255);
    }
    if (nm.contains('\\')) {
    qWarning("QtService: 'name' contains backslashes '\\'.");
    nm.replace((QChar)'\\', (QChar)'\0');
    }

    d_ptr = new QtServiceBasePrivate(nm);
    d_ptr->q_ptr = this;

    d_ptr->serviceFlags = 0;
    d_ptr->sysd = 0;
    for (int i = 0; i < argc; ++i)
        d_ptr->args.append(QString::fromLocal8Bit(argv[i]));
}

/*!
    Destroys the service object. This neither stops nor uninstalls the
    service.

    To stop a service the stop() function must be called
    explicitly. To uninstall a service, you can use the
    QtServiceController::uninstall() function.

    \sa stop(), QtServiceController::uninstall()
*/
QtServiceBase::~QtServiceBase()
{
    delete d_ptr;
    QtServiceBasePrivate::instance = 0;
}

/*!
    Returns the name of the service.

    \sa QtServiceBase(), serviceDescription()
*/
QString QtServiceBase::serviceName() const
{
    return d_ptr->controller.serviceName();
}

/*!
    Returns the description of the service.

    \sa setServiceDescription(), serviceName()
*/
QString QtServiceBase::serviceDescription() const
{
    return d_ptr->serviceDescription;
}

/*!
    Sets the description of the service to the given \a description.

    \sa serviceDescription()
*/
void QtServiceBase::setServiceDescription(const QString &description)
{
    d_ptr->serviceDescription = description;
}

/*!
    Returns the service's startup type.

    \sa QtServiceController::StartupType, setStartupType()
*/
QtServiceController::StartupType QtServiceBase::startupType() const
{
    return d_ptr->startupType;
}

/*!
    Sets the service's startup type to the given \a type.

    \sa QtServiceController::StartupType, startupType()
*/
void QtServiceBase::setStartupType(QtServiceController::StartupType type)
{
    d_ptr->startupType = type;
}

/*!
    Returns the service's state which is decribed using the
    ServiceFlag enum.

    \sa ServiceFlags, setServiceFlags()
*/
QtServiceBase::ServiceFlags QtServiceBase::serviceFlags() const
{
    return d_ptr->serviceFlags;
}

/*!
    \fn void QtServiceBase::setServiceFlags(ServiceFlags flags)

    Sets the service's state to the state described by the given \a
    flags.

    \sa ServiceFlags, serviceFlags()
*/

/*!
    Executes the service.

    When the exec() function is called, it will parse the \l
    {serviceSpecificArguments} {service specific arguments} passed in
    \c argv, perform the required actions, and exit.

    If none of the arguments is recognized as service specific, exec()
    will first call the createApplication() function, then executeApplication() and
    finally the start() function. In the end, exec()
    returns while the service continues in its own process waiting for
    commands from the service controller.

    \sa QtServiceController
*/
int QtServiceBase::exec()
{
    if (d_ptr->args.size() > 1) {
        QString a =  d_ptr->args.at(1);
        if (a == QLatin1String("-i") || a == QLatin1String("-install")) {
            if (!d_ptr->controller.isInstalled()) {
                QString account;
                QString password;
                if (d_ptr->args.size() > 2)
                    account = d_ptr->args.at(2);
                if (d_ptr->args.size() > 3)
                    password = d_ptr->args.at(3);
                if (!d_ptr->install(account, password)) {
                    fprintf(stderr, "Failed to install the service %s \n", serviceName().toLatin1().constData());
                    return -1;
                } else {
                    printf("Install the service %s successfully ! \n",serviceName().toLatin1().constData());
                }
            } else {
                fprintf(stderr, "The service %s is already installed \n", serviceName().toLatin1().constData());
            }
            return 0;
        } else if (a == QLatin1String("-u") || a == QLatin1String("-uninstall")) {
            if (d_ptr->controller.isInstalled()) {
                if (!d_ptr->controller.uninstall()) {
                    fprintf(stderr, "Failed to uninstall the service %s \n", serviceName().toLatin1().constData());
                    return -1;
                } else {
                    printf("Uninstall the service %s successfully !\n",
                        serviceName().toLatin1().constData());
                }
            } else {
                fprintf(stderr, "The service %s is not installed\n", serviceName().toLatin1().constData());
            }
            return 0;
        } else if (a == QLatin1String("-v") || a == QLatin1String("-version")) {
            printf("Sevice Name: %s\n",serviceName().toLatin1().constData());
            printf("Sevice Description: %s\n",serviceDescription().toLatin1().constData());
            printf("Sevice Installed: %s\n",(d_ptr->controller.isInstalled() ? "true" : "false"));
            printf("Sevice Running: %s\n",(d_ptr->controller.isRunning() ? "true" : "false"));
            return 0;
        } else if (a == QLatin1String("-e") || a == QLatin1String("-exec")) {
            d_ptr->args.removeAt(1);
            int ec = d_ptr->run(false, d_ptr->args);
            if (ec == -1){
                fprintf(stderr,"Failed to execute the service %s \n",serviceName().toLatin1().constData());
            }else{
                printf("Execute the service %s successfully !\n",serviceName().toLatin1().constData());
            };
            return ec;
        } else if (a == QLatin1String("-t") || a == QLatin1String("-terminate")) {
            if (!d_ptr->controller.stop()){
                fprintf(stderr, "Failed to terminate the service %s\n",serviceName().toLatin1().constData());
                return -1;
            }else{
                printf("Terminate the service %s successfully !\n",serviceName().toLatin1().constData());
                return 0;
            }
        } else if (a == QLatin1String("-p") || a == QLatin1String("-pause")) {
            if(!d_ptr->controller.pause()){
                fprintf(stderr, "Failed to pause the service %s\n",serviceName().toLatin1().constData());
                return -1;
            }else{
                printf("Pause the service %s successfully !\n",serviceName().toLatin1().constData());
                return 0;
            }
        } else if (a == QLatin1String("-r") || a == QLatin1String("-resume")) {
            if(!d_ptr->controller.resume()){
                fprintf(stderr, "Failed to resume the service %s\n",serviceName().toLatin1().constData());
                return -1;
            }else{
                printf("Resume the service %s successfully !\n",serviceName().toLatin1().constData());
                return 0;
            }
        } else if (a == QLatin1String("-c") || a == QLatin1String("-command")) {
            int code = 0;
            if (d_ptr->args.size() > 2)
                code = d_ptr->args.at(2).toInt();

            if(!d_ptr->controller.sendCommand(code)){
                fprintf(stderr, "Failed to sendCommand to the service %s\n",serviceName().toLatin1().constData());
                return -1;
            }else{
                printf("SendCommand to the service %s successfully !\n",serviceName().toLatin1().constData());
                return 0;
            }
        } else  if (a == QLatin1String("-h") || a == QLatin1String("-help")) {
            printf("\n%s -[i|u|e|t|p|r|c|v|h]\n"
                   "\t-i(nstall) [account] [password]\t: Install the service, optionally using given account and password\n"
                   "\t-u(ninstall)\t: Uninstall the service.\n"
                   "\t-e(xec)\t\t: Run as a regular application. Useful for debugging.\n"
                   "\t-t(erminate)\t: Stop the service.\n"
                   "\t-p(ause)\t: Pause the service.\n"
                   "\t-r(esume)\t: Resume a paused service.\n"
                   "\t-c(ommand) num\t: Send command code num to the service.\n"
                   "\t-v(ersion)\t: Print version and status information.\n"
                   "\t-h(elp)   \t: Show this help\n"
                   "\tNo arguments\t: Start the service.\n",
                   d_ptr->args.at(0).toLatin1().constData());
            return 0;
        }
    }
#if defined(Q_OS_UNIX)
    if (::getenv("QTSERVICE_RUN")) {
        // Means we're the detached, real service process.
        int ec = d_ptr->run(true, d_ptr->args);
        if (ec == -1)
            qErrnoWarning("The service failed to run.");
        return ec;
    }
#endif
    if (!d_ptr->start()){
        fprintf(stderr, "Failed to start the service %s\n",serviceName().toLatin1().constData());
        return -1;
    }else{
        printf("Start the service %s successfully !\n",serviceName().toLatin1().constData());
        return 0;
    }
}

/*!
    \fn void QtServiceBase::logMessage(const QString &message, MessageType type,
            int id, uint category, const QByteArray &data)

    Reports a message of the given \a type with the given \a message
    to the local system event log.  The message identifier \a id and
    the message \a category are user defined values. The \a data
    parameter can contain arbitrary binary data.

    Message strings for \a id and \a category must be provided by a
    message file, which must be registered in the system registry.
    Refer to the MSDN for more information about how to do this on
    Windows.

    \sa MessageType
*/

/*!
    Returns a pointer to the current application's QtServiceBase
    instance.
*/
QtServiceBase *QtServiceBase::instance()
{
    return QtServiceBasePrivate::instance;
}

/*!
    \fn void QtServiceBase::start()

    This function must be implemented in QtServiceBase subclasses in
    order to perform the service's work. Usually you create some main
    object on the heap which is the heart of your service.

    The function is only called when no service specific arguments
    were passed to the service constructor, and is called by exec()
    after it has called the executeApplication() function.

    Note that you \e don't need to create an application object or
    call its exec() function explicitly.

    \sa exec(), stop(), QtServiceController::start()
*/

/*!
    Reimplement this function to perform additional cleanups before
    shutting down (for example deleting a main object if it was
    created in the start() function).

    This function is called in reply to controller requests. The
    default implementation does nothing.

    \sa start(), QtServiceController::stop()
*/
void QtServiceBase::stop()
{
}

/*!
    Reimplement this function to pause the service's execution (for
    example to stop a polling timer, or to ignore socket notifiers).

    This function is called in reply to controller requests.  The
    default implementation does nothing.

    \sa resume(), QtServiceController::pause()
*/
void QtServiceBase::pause()
{
}

/*!
    Reimplement this function to continue the service after a call to
    pause().

    This function is called in reply to controller requests. The
    default implementation does nothing.

    \sa pause(), QtServiceController::resume()
*/
void QtServiceBase::resume()
{
}

/*!
    Reimplement this function to process the user command \a code.


    This function is called in reply to controller requests.  The
    default implementation does nothing.

    \sa QtServiceController::sendCommand()
*/
void QtServiceBase::processCommand(int /*code*/)
{
}

void QtServiceBase::logMessage(const QString &message, MessageType type,
                           int id, uint category, const QByteArray &data)
{
#if defined(QTSERVICE_DEBUG)
    QByteArray dbgMsg("[LOGGED ");
    switch (type) {
    case Error: dbgMsg += "Error] " ; break;
    case Warning: dbgMsg += "Warning] "; break;
    case Success: dbgMsg += "Success] "; break;
    case Information: //fall through
    default: dbgMsg += "Information] "; break;
    }
#  if QT_VERSION >= 0x050000
    qtServiceLogDebug((QtMsgType)-1, QMessageLogContext(), QLatin1String(dbgMsg) + message);
#  else
    qtServiceLogDebug((QtMsgType)-1, (dbgMsg + message.toAscii()).constData());
#  endif
#endif

    Q_D(QtServiceBase);
    if (!winServiceInit())
        return;
    WORD wType;
    switch (type) {
    case Error: wType = EVENTLOG_ERROR_TYPE; break;
    case Warning: wType = EVENTLOG_WARNING_TYPE; break;
    case Information: wType = EVENTLOG_INFORMATION_TYPE; break;
    default: wType = EVENTLOG_SUCCESS; break;
    }
    HANDLE h = pRegisterEventSource(0, (wchar_t *)d->controller.serviceName().utf16());
    if (h) {
        const wchar_t *msg = (wchar_t*)message.utf16();
        const char *bindata = data.size() ? data.constData() : 0;
        pReportEvent(h, wType, category, id, 0, 1, data.size(),(const wchar_t **)&msg,
                     const_cast<char *>(bindata));
        pDeregisterEventSource(h);
    }
}
